﻿using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Phoenix.Xna.Framework.Components.Cameras;

namespace Phoenix.Xna.Framework.Graphics.Models
{
    public class InstancedModel : ModelBase
    {
        [ContentSerializer]
        private List<InstancedModelPart> _modelParts = null;
        private List<Matrix> _visibleTransforms = new List<Matrix>();
        private InstancingTechnique _instancingTechnique;

        [ContentSerializerIgnore]
        public List<Matrix> InstanceTransforms { get; set; }
        [ContentSerializerIgnore]
        public InstancingTechnique InstancingTechnique
        {
            get { return _instancingTechnique; }
            set
            {
                _instancingTechnique = value;

                foreach (InstancedModelPart modelPart in _modelParts)
                {
                    modelPart.SetInstancingTechnique(_instancingTechnique);
                }
            }
        }

        private InstancedModel()
            : base()
        {
            InstanceTransforms = new List<Matrix>();
        }

        protected bool IsTechniqueSupported(InstancingTechnique technique)
        {
#if !XBOX360
            if (technique == InstancingTechnique.HardwareInstancing)
            {
                return Engine.Instance.GraphicsDevice.GraphicsDeviceCapabilities.PixelShaderVersion.Major >= 3;
            }
#endif

            return true;
        }

        #region IComponent Members

        public override void Initialize()
        {
            base.Initialize();

            foreach (InstancedModelPart modelPart in _modelParts)
            {
                modelPart.Initialize(Engine.Instance.GraphicsDevice);
            }

            InstancingTechnique technique = 0;

            while (!IsTechniqueSupported(technique))
            {
                technique++;
            }

            InstancingTechnique = technique;
        }

        public override void Update(GameTime gameTime)
        {
            if (Enabled)
            {
                _visibleTransforms.Clear();

                foreach (Matrix m in InstanceTransforms)
                {
                    if (Vector3.Distance(m.Translation, Camera.ActiveCamera.Position) <= 2000)
                    {
                        _visibleTransforms.Add(m);
                    }
                }

                base.Update(gameTime);
            }
        }

        #endregion

        #region IDrawableComponent Members

        public override void Draw(GameTime gameTime)
        {
            if (Visible)
            {
                if (_visibleTransforms.Count == 0)
                {
                    return;
                }

                foreach (InstancedModelPart modelPart in _modelParts)
                {
                    modelPart.Draw(InstancingTechnique, _visibleTransforms);
                }

                base.Draw(gameTime);
            }
        }

        #endregion
    }
}
